﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMathLibrary
{
    /// <summary>
    /// This class provides methods to manipulate individual bits in numeric data types.
    /// </summary>
    [Serializable]
    public static class BitOperations
    {
        /// <summary>
        /// Determines whether the bit at the specified n is set in the specified value parameter.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <returns>
        /// True if the bit at the specified position is set otherwise, false.
        /// </returns>
        public static bool IsBitSet(long value, int n)
        {
            if ((value & ((long) 1 << n)) > 0)
            {
                return true;
            }

            return false;

            //if ((value & (1 << n)) == 1)
            //{
            //    return true;
            //}

            //return false;
        }

        /// <summary>
        /// Determines whether the bit at the specified n is set in the specified value parameter.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <returns>
        /// True if the bit at the specified position is set otherwise, false.
        /// </returns>
        public static bool IsBitSet(int value, int n)
        {
            if ((value & ((int) 1 << n)) > 0)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Determines whether the bit at the specified n is set in the specified value parameter.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <returns>
        /// True if the bit at the specified position is set otherwise, false.
        /// </returns>
        public static bool IsBitSet(uint value, int n)
        {
            if ((value & ((int) 1 << n)) > 0)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Determines whether the bit at the specified n is set in the specified value parameter.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <returns>
        /// True if the bit at the specified position is set otherwise, false.
        /// </returns>
        public static bool IsBitSet(UInt64 value, int n)
        {
            if ((value & ((UInt64) 1 << n)) > 0)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Sets the bit at the specified position n.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <returns>The manipulated value.</returns>
        public static long SetBit(long value, int n)
        {
            value = value | ((long) 1 << n);

            return value;
        }

        /// <summary>
        /// Sets the bit at the specified position n.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <returns>The manipulated value.</returns>
        public static int SetBit(int value, int n)
        {
            value = value | ((int) 1 << n);

            return value;
        }

        /// <summary>
        /// Sets the bit at the specified position n.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <returns>The manipulated value.</returns>
        public static uint SetBit(uint value, int n)
        {
            value = value | ((uint) 1 << n);

            return value;
        }

        /// <summary>
        /// Sets the bit at the specified position n.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <returns>The manipulated value.</returns>
        public static UInt64 SetBit(UInt64 value, int n)
        {
            value = value | ((UInt64) 1 << n);

            return value;
        }

        /// <summary>
        /// Sets the bit at the specified position n.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <param name="state">The value to set at the specified position.</param>
        /// <returns>The manipulated value.</returns>
        public static long SetBit(long value, int n, bool state)
        {
            if (state)
            {
                return BitOperations.SetBit(value, n);
            }

            return BitOperations.UnsetBit(value, n);
        }

        /// <summary>
        /// Sets the bit at the specified position n.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <param name="state">The value to set at the specified position.</param>
        /// <returns>The manipulated value.</returns>
        public static int SetBit(int value, int n, bool state)
        {
            if (state)
            {
                return BitOperations.SetBit(value, n);
            }

            return BitOperations.UnsetBit(value, n);
        }

        /// <summary>
        /// Sets the bit at the specified position n.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <param name="state">The value to set at the specified position.</param>
        /// <returns>The manipulated value.</returns>
        public static uint SetBit(uint value, int n, bool state)
        {
            if (state)
            {
                return BitOperations.SetBit(value, n);
            }

            return BitOperations.UnsetBit(value, n);
        }

        /// <summary>
        /// Sets the bit at the specified position n.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <param name="state">The value to set at the specified position.</param>
        /// <returns>The manipulated value.</returns>
        public static UInt64 SetBit(UInt64 value, int n, bool state)
        {
            if (state)
            {
                return BitOperations.SetBit(value, n);
            }

            return BitOperations.UnsetBit(value, n);
        }

        /// <summary>
        /// Unsets the bit at the specified position n.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <returns>The manipulated value.</returns>
        public static long UnsetBit(long value, int n)
        {
            value = value & ~(1 << n);

            return value;
        }

        /// <summary>
        /// Unsets the bit at the specified position n.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <returns>The manipulated value.</returns>
        public static int UnsetBit(int value, int n)
        {
            value = value & ~(1 << n);

            return value;
        }

        /// <summary>
        /// Unsets the bit at the specified position n.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <returns>The manipulated value.</returns>
        public static uint UnsetBit(uint value, int n)
        {
            value = value & ~((uint) 1 << n);

            return value;
        }

        /// <summary>
        /// Unsets the bit at the specified position n.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <returns>The manipulated value.</returns>
        public static UInt64 UnsetBit(UInt64 value, int n)
        {
            value = value & ~((UInt64) 1 << n);

            return value;
        }

        /// <summary>
        /// Inverts the bit at the specified position n.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <returns>The manipulated value.</returns>
        public static long InvertBit(long value, int n)
        {
            value = value ^ (1 << n);

            return value;
        }

        /// <summary>
        /// Inverts the bit at the specified position n.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <returns>The manipulated value.</returns>
        public static int InvertBit(int value, int n)
        {
            value = value ^ (1 << n);

            return value;
        }

        /// <summary>
        /// Inverts the bit at the specified position n.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The position n.</param>
        /// <returns>The manipulated value.</returns>
        public static uint InvertBit(uint value, int n)
        {
            value = value ^ ((uint) 1 << n);

            return value;
        }

        /// <summary>
        /// Rotates the sequence of bits n-times right. If the rotation value is negative the sequence of bits will rotate in the other direction.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The rotation value n.</param>
        /// <returns>The manipulated value.</returns>
        public static int RotateRight(long value, int n)
        {
            if (n < 0)
            {
                return BitOperations.RotateLeft(value, -n);
            }

            uint num = (uint) value;
            const int length = (sizeof (long) * 8);

            n = n % length;

            uint add = num << (length - n);

            num = num >> n;
            num = num | add;

            return (int) num;
        }

        /// <summary>
        /// Rotates the sequence of bits n-times left. If the rotation value is negative the sequence of bits will rotate in the other direction.
        /// </summary>
        /// <param name="value">The specified value parameter.</param>
        /// <param name="n">The rotation value n.</param>
        /// <returns>The manipulated value.</returns>
        public static int RotateLeft(long value, int n)
        {
            if (n < 0)
            {
                return BitOperations.RotateRight(value, -n);
            }

            uint num = (uint) value;
            const int length = (sizeof (long) * 8);

            n = n % length;

            uint add = num >> (length - n);

            num = num << n;
            num = num | add;

            return (int) num;
        }
    }
}